/*
 * Compile with:
 * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
 */

#ifdef HAVE_SYS_TYPES_H
#    include <sys/types.h>
#endif
#include <sys/stat.h>
#ifndef WIN32
#    ifdef HAVE_SYS_QUEUE_H
#        include <sys/queue.h>
#    endif
#    ifdef HAVE_UNISTD_H
#        include <unistd.h>
#    endif
#    ifdef HAVE_SYS_TIME_H
#        include <sys/time.h>
#    endif
#else
#    include <windows.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "opal/runtime/opal.h"
#include "opal/util/event.h"

static void fifo_read(int fd, short event, void *arg)
{
    char buf[255];
    int len;
    opal_event_t *ev = arg;
#ifdef WIN32
    DWORD dwBytesRead;
#endif

    /* Reschedule this event */
    opal_event.add(ev, NULL);

    fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n", fd, event, arg);
#ifdef WIN32
    len = ReadFile((HANDLE) fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL);

    /* Check for end of file. */
    if (len && dwBytesRead == 0) {
        fprintf(stderr, "End Of File");
        opal_event.del(ev);
        return;
    }

    buf[dwBytesRead + 1] = '\0';
#else
    len = read(fd, buf, sizeof(buf) - 1);

    if (len == -1) {
        perror("read");
        return;
    } else if (len == 0) {
        fprintf(stderr, "Connection closed\n");
        return;
    }

    buf[len] = '\0';
#endif
    fprintf(stdout, "Read: %s\n", buf);
}

int main(int argc, char **argv)
{
    opal_event_t evfifo;
#ifdef WIN32
    HANDLE socket;
    // Open a file.
    socket = CreateFile("test.txt",            // open File
                        GENERIC_READ,          // open for reading
                        0,                     // do not share
                        NULL,                  // no security
                        OPEN_EXISTING,         // existing file only
                        FILE_ATTRIBUTE_NORMAL, // normal file
                        NULL);                 // no attr. template

    if (socket == INVALID_HANDLE_VALUE)
        return 1;

#else
    struct stat st;
    char *fifo = "event.fifo";
    int socket;

    if (lstat(fifo, &st) == 0) {
        if ((st.st_mode & S_IFMT) == S_IFREG) {
            errno = EEXIST;
            perror("lstat");
            exit(1);
        }
    }

    unlink(fifo);
    if (mkfifo(fifo, 0600) == -1) {
        perror("mkfifo");
        exit(1);
    }

    /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
#    ifdef __linux
    socket = open(fifo, O_RDWR | O_NONBLOCK, 0);
#    else
    socket = open(fifo, O_RDONLY | O_NONBLOCK, 0);
#    endif

    if (socket == -1) {
        perror("open");
        exit(1);
    }

    fprintf(stderr, "Write data to %s\n", fifo);
#endif
    /* Initialize the event library */
    opal_init();

    /* Initialize one event */
#ifdef WIN32
    opal_event.set(opal_event_base, &evfifo, (int) socket, OPAL_EV_READ, fifo_read, &evfifo);
#else
    opal_event.set(opal_event_base, &evfifo, socket, OPAL_EV_READ, fifo_read, &evfifo);
#endif

    /* Add it to the active events, without a timeout */
    opal_event.add(&evfifo, NULL);

    opal_event.dispatch(opal_event_base);
#ifdef WIN32
    CloseHandle(socket);
#endif
    return (0);
}
